AtCoder Beginner Contest 346 A-G 题解
A - Adjacent Product
Question
给你
按此顺序打印
Solution
按照题意模拟
Code
#include<bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
vector<int> a(n + 1);
for (int i = 1; i <= n; i++)
cin >> a[i];
for (int i = 1; i < n; i++)
cout << a[i] * a[i + 1] << " ";
return 0;
}
B - Piano
Question
有一个无限长的钢琴键盘。在这个键盘中,是否存在一个由
假设 wbwbwwbwbwbw 构成的字符串。
在 w 和 b 组成的子串?
Solution
暴力把
应该还有更优的解法,只是串长实在太短,怎么写都行
Code
#include <bits/stdc++.h>
using namespace std;
int main() {
int W, B; cin >> W >> B;
string s, p = "wbwbwwbwbwbw";
while (s.size() < 2000) s += p;
int n = s.size(); s = " " + s;
vector<int> sumb(n + 1), sumw(n + 1);
for (int i = 1; i <= n; i++) {
sumb[i] = sumb[i - 1] + (s[i] == 'b');
sumw[i] = sumw[i - 1] + (s[i] == 'w');
}
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++) {
int nw = sumw[j] - sumw[i - 1], nb = sumb[j] - sumb[i - 1];
if (W == nw && B == nb) {
cout << "Yes" << endl;
return 0;
}
}
cout << "No" << endl;
return 0;
}
C - Σ
Question
给你一个长度为
求在
Solution
先算
注意
Code
#include <bits/stdc++.h>
#define int long long
using namespace std;
signed main() {
ios::sync_with_stdio(0); cin.tie(0);
int n, k; cin >> n >> k;
vector<int> a(n);
for (int &x : a) cin >> x;
sort(a.begin(), a.end());
a.erase(unique(a.begin(), a.end()), a.end());
int ans = k * (k + 1) / 2;
for (int &x : a) {
if (x <= k)
ans -= x;
}
cout << ans << endl;
return 0;
}
D - Gomamayo Sequence
Question
给你一个长度为 0 和 1 组成
长度为 0 和 1 组成,当且仅当它满足以下条件时,它是一个好字符串:
- 恰好有一个整数
使得 和 的第 个字母 和第 个字符相同
对于每个
- 如果
的 个字符是 0,则将其替换为1,反之亦然。如果执行此操作,代价是
求使
Solution
考虑到有且仅有一个
0101 交替的,我们就可以记录一个交错的前缀和
定义 0101 交替的,且第 0 花费的最小代价,0101 交替的,且第 1 花费的最小代价
同理,0101 交替的,且第 0 花费的最小代价
如何计算
for (int i = 1; i <= n; i++) {
pre[i][0] = pre[i - 1][1] + c[i] * (s[i] != '0');
pre[i][1] = pre[i - 1][0] + c[i] * (s[i] != '1');
}
最后,关于
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll INF = 1e18;
int main() {
ios::sync_with_stdio(0); cin.tie(0);
int n; cin >> n;
string s; cin >> s; s = " " + s;
vector<ll> c(n + 1, 0);
for (int i = 1; i <= n; i++)
cin >> c[i];
vector<vector<ll> > pre(n + 2 , vector<ll>(2, 0)); auto lst = pre;
for (int i = 1; i <= n; i++) {
pre[i][0] = pre[i - 1][1] + c[i] * (s[i] != '0');
pre[i][1] = pre[i - 1][0] + c[i] * (s[i] != '1');
}
for (int i = n; i > 0; i--) {
lst[i][0] = lst[i + 1][1] + c[i] * (s[i] != '0');
lst[i][1] = lst[i + 1][0] + c[i] * (s[i] != '1');
}
ll ans = INF;
//00
for (int i = 1; i < n; i++) {
ll now = c[i] * (s[i] != '0') + c[i + 1] * (s[i + 1] != '0');
now += pre[i - 1][1] + lst[i + 2][1];
ans = min(ans, now);
}
//11
for (int i = 1; i < n; i++) {
ll now = c[i] * (s[i] != '1') + c[i + 1] * (s[i + 1] != '1');
now += pre[i - 1][0] + lst[i + 2][0];
ans = min(ans, now);
}
cout << ans << '\n';
return 0;
}
E - Paint
Question
有一个行数为
您将按照
-
如果是
,则使用颜色 重新绘制 行中的所有单元格。 -
如果是
,则使用颜色 重新绘制 列中的所有单元格
完成所有操作后,针对网格中存在的每种颜色
Solution
显然,最后一次刷在墙上的颜色肯定存在,第二次如果和第一次方向不同,那么中间会有一个格子是第一次刷的颜色
按照这个想法,我们用 map 记录有多少行被刷了颜色,以及有多少列刷了颜色
倒叙处理,这一行/列 在这一次刷中保留了多少颜色,取决与有多少 列/行 还没有刷过
Code
#include <bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int,int> pii;
signed main() {
freopen ("E.in","r",stdin);
ios::sync_with_stdio(0); cin.tie(0);
int H, W, N; cin >> H >> W >> N;
vector<int> A(N + H), X(N + H), T(N + H);
N = N + H;
for (int i = 0; i < H; i++) {
T[i] = 1; A[i] = i + 1; X[i] = 0;
}
for (int i = H; i < N; i++)
cin >> T[i] >> A[i] >> X[i];
map<int,pii> col, row;
for (int i = N - 1; i>= 0; i--) {
if (T[i] == 1) {
if (row.count(A[i])) continue;
row[A[i]] = {W - col.size(), X[i]};
}
else {
if (col.count(A[i])) continue;
col[A[i]] = {H - row.size(), X[i]};
}
}
map<int,int> mp;
for (auto &r : row) {
int num = r.second.first, c = r.second.second;
if (!mp.count(c))
mp[c] = 0;
mp[c] += num;
}
for (auto &r : col) {
int num = r.second.first, c = r.second.second;
if (!mp.count(c))
mp[c] = 0;
mp[c] += num;
}
int ans = 0;
for (auto &x : mp)
ans += x.second != 0;
cout << ans << '\n';
for (auto &x : mp) {
if (x.second == 0) continue;
cout << x.first << " " << x.second << '\n';
}
return 0;
}
F - SSttrriinngg in StringString
Question
对于长度为
- 让
表示重复 次字符串 得到的字符串 表示依次重复 次第一个字符、第二个字符、 、 的 个字符得到的字符串
给你一个正整数
注意,根据定义,
Solution
答案满足单调性,也就是说,如果
所以我们二分最后的答案
提前预处理出
记录此时枚举
对于
按照题意模拟即可
Code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll INF = 1ll << 60;
int main() {
ll n;
string S, T;
cin >> n >> S >> T;
int s = S.size(), t = T.size();
vector<vector<int> > pos(26);
for (int i = 0; i < s * 2; i++)
pos[S[i % s] - 'a'].push_back(i);
vector<vector<int> > pre(s + 1, vector<int>(26));
for (int i = 0; i < s; i++) {
pre[i + 1] = pre[i];
pre[i + 1][S[i] - 'a']++;
}
vector<int> cnt(26, 0);
for (int i = 0; i < s; i++)
cnt[S[i] - 'a']++;
ll le = 0, ri = INF;
auto check = [&] (ll x) -> bool {
ll iter = 0; // 表示s的长度
for (int i = 0; i < t; i++) {
int c = T[i] - 'a';
if (cnt[c] == 0) return false;
ll r = (x - 1) % cnt[c] + 1;
ll q = (x - r) / cnt[c];
if (q > INF / s) return false;
iter += q * s;
int nx = pos[c][pre[iter % s][c] + r - 1]; // 从iter % s开始的第r个c 的位置
iter += nx - iter % s + 1;
if (iter > n * s) return false;
}
return true;
};
while (le + 1 < ri) {
ll mid = (le + ri) >> 1;
if (check(mid)) le = mid;
else ri = mid;
}
cout << le << endl;
return 0;
}
G - Alone
Question
给你一个整数序列
求满足以下条件的整数对
- 有一个数字在
中恰好出现一次。更确切地说,有一个整数 恰好有一个整数 满足 和
Solution
对于一个
显然,一个区间的左端点可以在
例如 2 2 1 2 1 ,当
那么此时的
对于一个
关键是如何去重? 我们发现一个
而矩形的左下角是
显然,这个问题就转化为二维平面上
利用扫描线算法就可以解决
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
struct Segment_Tree {
int n;
vector<int> sum, tag;
Segment_Tree (int n) {
this->n = n;
tag.assign(n << 4, 0);
sum.assign(n << 4, 0);
}
void update (int x, int l, int r, int ql, int qr, int val) {
if (ql <= l && r <= qr) {
tag[x] += val;
if (tag[x]) sum[x] = r - l + 1;
else sum[x] = sum[x << 1] + sum[x << 1 | 1];
return ;
}
int mid = (l + r) >> 1;
if (ql <= mid) update(x << 1, l, mid, ql, qr, val);
if (qr > mid) update(x << 1 | 1, mid + 1, r, ql, qr, val);
if (!tag[x]) sum[x] = sum[x << 1] + sum[x << 1 | 1];
}
};
struct Line {
int l, r, x, op;
Line (int l, int r, int x, int op) : l(l), r(r), x(x), op(op) {}
bool operator < (const Line &rhs) {
if (x == rhs.x) return op < rhs.op;
return x < rhs.x;
}
};
int main() {
freopen ("G.in", "r", stdin);
int n; cin >> n;
vector<int> a(n + 1);
for (int i = 1; i <= n; i++)
cin >> a[i];
vector<int> pre(n + 1, 0), nxt(n + 1, n + 1), pos(n + 1, 0);
for (int i = 1; i <= n; i++) {
pre[i] = pos[a[i]];
pos[a[i]] = i;
}
pos.assign(n + 1, n + 1);
for (int i = n; i; i--) {
nxt[i] = pos[a[i]];
pos[a[i]] = i;
}
vector<Line> lines;
for (int i = 1; i <= n; i++) {
lines.emplace_back(i, nxt[i] - 1, pre[i], 1);
lines.emplace_back(i, nxt[i] - 1, i, -1);
}
Segment_Tree T(n);
ll ans = 0;
sort(lines.begin(), lines.end());
for (int i = 0; i < lines.size() - 1; i++) {
T.update(1, 1, n, lines[i].l, lines[i].r, lines[i].op);
ans += 1ll * T.sum[1] * (lines[i + 1].x - lines[i].x);
}
cout << ans << endl;
return 0;
}